//#include <NTDDK.h>
#include <ifs/wnet/ntifs.h>
//#include <wdm.h>

VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);
NTSTATUS DriverEntry (
    IN PDRIVER_OBJECT pDriverObject,
    IN PUNICODE_STRING pRegistryPath	);

#pragma alloc_text(init, DriverEntry)
#pragma alloc_text(page, DriverUnload)

static PDEVICE_OBJECT dev_obj = NULL;

#define IO_BITMAP_SIZE	32
struct tss_struct {
	unsigned short	back_link,__blh;
	unsigned long	esp0;
	unsigned short	ss0,__ss0h;
	unsigned long	esp1;
	unsigned short	ss1,__ss1h;
	unsigned long	esp2;
	unsigned short	ss2,__ss2h;
	unsigned long	cr3;
	unsigned long	eip;
	unsigned long	eflags;
	unsigned long	eax,ecx,edx,ebx;
	unsigned long	esp;
	unsigned long	ebp;
	unsigned long	esi;
	unsigned long	edi;
	unsigned short	es, __esh;
	unsigned short	cs, __csh;
	unsigned short	ss, __ssh;
	unsigned short	ds, __dsh;
	unsigned short	fs, __fsh;
	unsigned short	gs, __gsh;
	unsigned short	ldt, __ldth;
	unsigned short	trace, bitmap;
	unsigned long	io_bitmap[IO_BITMAP_SIZE+1];
	unsigned long	tr;
	unsigned long	cr2, trap_no, error_code;
//	union i387_union i387;
};

#pragma pack(1)

typedef struct
{
    short limit;
	ULONG base;
} IDTR; // GDTR and IDTR format

typedef struct
{
	short offs_l;
	short sel;
	short attrib;
	short offs_h;
} DESC; 

typedef struct
{
	unsigned short limit;
	unsigned short base_l;
	unsigned char base_m;
	unsigned short type;
	unsigned char base_h;
} TSS;
	
#pragma pack()

VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject)
{
	if (dev_obj)
	{
		IoDeleteDevice(dev_obj);
		dev_obj = NULL;
	}
	KdPrint(("task : %s \n", __FUNCTION__));	
}

static NTSTATUS ignore(IN struct _DEVICE_OBJECT *DeviceObject, IN struct _IRP *Irp)
{
	PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);

	IoCompleteRequest(Irp, IO_NO_INCREMENT);	
	return STATUS_SUCCESS;
}

static int find_tss(IDTR gdt)
{
	int i;
	TSS *tss;
	for (i = 0; i < gdt.limit; ++i)
	{
		tss = (TSS *)(gdt.base + i * 8);
		if ((tss->type & 0xf) == 0x09)
			break;
		if ((tss->type & 0xf) == 0x0b)
			break;		
	}
	return (0);
}

static NTSTATUS task_read(IN struct _DEVICE_OBJECT *DeviceObject, IN struct _IRP *Irp)
{
	PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
	unsigned short testcs;
	unsigned short testss;
	unsigned short testds;
	unsigned short testes;
	unsigned short testfs;
	unsigned short testgs;
	unsigned short testtr;
	unsigned short trindex;
	unsigned long testcr3;
	IDTR testgdt, testidt;
	TSS *tss = NULL;
	struct tss_struct *tss_para = NULL;

	__asm{
		mov testcs, cs;
		mov testss, ss;
		mov testds, ds;
		mov testes, es;
		mov testfs, fs;
		mov testgs, gs;
		sgdt [testgdt];
		sidt [testidt];
		str [testtr];
		mov eax, cr3;
		mov testcr3, eax;
//		mov eax, cr4;
//		mov testcr4, eax;		
	};

	KdPrint(("%s stack at %p, ip at %p\n", 
			__FUNCTION__, &testcr3, task_read));

	trindex = testtr & 0xfff8;
	KdPrint(("%s cr3[%x] gdt[%x] tr[%hx][%hx] cs[%hx]\n", 
			__FUNCTION__, testcr3, testgdt.base, testtr, (trindex >> 3), testcs));
//	find_tss(testgdt);

	tss = (TSS *)(testgdt.base + trindex);

	KdPrint(("%s limit[%04hx] base[%02hhx][%02hhx][%04hx] type[%04hx]\n", 
			__FUNCTION__, tss->limit, tss->base_h & 0xff, tss->base_m & 0xff, tss->base_l & 0xffff, tss->type));

	tss_para = (struct tss_struct *)(tss->base_h << 24 | tss->base_m << 16 | tss->base_l);

	tss_para = (struct tss_struct *)((tss->base_h & 0xff) << 24 | (tss->base_m & 0xff)<< 16 | (tss->base_l & 0xffff));
	
	IoCompleteRequest(Irp, IO_NO_INCREMENT);	
	return STATUS_SUCCESS;
}

NTSTATUS DriverEntry (
    IN PDRIVER_OBJECT pDriverObject,
    IN PUNICODE_STRING pRegistryPath	)
{
	NTSTATUS ret;
	UNICODE_STRING name, link_name;
	
	KdPrint(("task : %s \n", __FUNCTION__));
	pDriverObject->DriverUnload = DriverUnload;

	pDriverObject->MajorFunction[IRP_MJ_CREATE] = ignore;
	pDriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = ignore;
	pDriverObject->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = ignore;
	pDriverObject->MajorFunction[IRP_MJ_READ] = task_read;
	pDriverObject->MajorFunction[IRP_MJ_WRITE] = ignore;
	
	RtlInitUnicodeString(&name, L"\\FileSystem\\testtask");
	ret = IoCreateDevice(pDriverObject, 0, &name, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev_obj);
	if (ret != STATUS_SUCCESS) {
		KdPrint(("task : %s : IoCreateDevice fail[0x%x]\n", __FUNCTION__, ret));
		return STATUS_SUCCESS;	
	}

	RtlInitUnicodeString(&link_name, L"\\??\\testtask_link");
	IoDeleteSymbolicLink(&link_name);
	ret = IoCreateSymbolicLink(&link_name, &name);
	if (ret != STATUS_SUCCESS) {
		KdPrint(("task : %s : IoCreateSymbolicLink fail[0x%x]\n", __FUNCTION__, ret));
		return STATUS_SUCCESS;	
	}
	
	SetFlag(dev_obj->Flags, DO_BUFFERED_IO );
	SetFlag(dev_obj->Characteristics, FILE_DEVICE_SECURE_OPEN );
    ClearFlag(dev_obj->Flags, DO_DEVICE_INITIALIZING);
	
	return STATUS_SUCCESS;
}


